package com.icesoft.test.token;


import com.icesoft.core.common.util.JsonUtil;
import com.icesoft.core.common.util.UuidUtil;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;

public final class Auth {

    public final String accessKey;
    private final SecretKeySpec secretKey;
    private final String application;

    private Auth(String accessKey, SecretKeySpec secretKeySpec, String application) {
        this.accessKey = accessKey;
        this.secretKey = secretKeySpec;
        this.application = application;
    }

    public static Auth create(String accessKey, String secretKey, String application) {
        byte[] sk = utf8Bytes(secretKey);
        SecretKeySpec secretKeySpec = new SecretKeySpec(sk, "HmacSHA1");
        return new Auth(accessKey, secretKeySpec, application);
    }

    /**
     * 获取token
     * <p>
     * 有效时长，3600秒
     *
     * @return 生成的上传token
     */
    public String uploadToken() {
        return uploadToken(true);
    }

    /**
     * 获取token
     * <p>
     * 有效时长，3600秒
     *
     * @param security 上传的文件是否需要token访问
     * @return 生成的上传token
     */
    public String uploadToken(boolean security) {
        return uploadToken(security, 3600);
    }

    /**
     * 获取token
     *
     * @param expires 有效时长，单位秒
     * @return 生成的上传token
     */
    public String uploadToken(boolean security, long expires) {
        return uploadToken(security, expires, UuidUtil.getUUID(6));
    }

    /**
     * 生成上传token
     *
     * @param expires  有效时长，单位秒
     * @param nonceStr 随机字符串
     * @return 生成的上传token
     */
    public String uploadToken(boolean security, long expires, String nonceStr) {
        long deadline = System.currentTimeMillis() / 1000 + expires;
        TokenInfo tokenInfo = TokenInfo.builder().security(security).application(application).deadline(deadline).nonceStr(nonceStr).build();
        return uploadToken(tokenInfo);
    }

    public String uploadToken(TokenInfo tokenInfo) {
        String s = JsonUtil.toJson(tokenInfo);
        return signWithData(utf8Bytes(s));
    }

    public static TokenInfo decodeToken(String token) {
        String tokenArr[] = token.split(":");
        String json = UrlSafeBase64.decodeToString(tokenArr[2]);
        return JsonUtil.toObject(json, TokenInfo.class);
    }

    private static byte[] utf8Bytes(String data) {
        return data.getBytes(StandardCharsets.UTF_8);
    }


    private Mac createMac() {
        Mac mac;
        try {
            mac = Mac.getInstance("HmacSHA1");
            mac.init(secretKey);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
            throw new IllegalArgumentException(e);
        }
        return mac;
    }

    private String signWithData(byte[] data) {

        String s = UrlSafeBase64.encodeToString(data);
        return sign(utf8Bytes(s)) + ":" + s;
    }

    private String sign(byte[] data) {
        Mac mac = createMac();
        return accessKey + ":" + UrlSafeBase64.encodeToString(mac.doFinal(data));
    }

}
